const fp = require('fastify-plugin');

async function mysqlKnex(fastify, options) {
  const knex = require('knex')({
    client: 'mysql',
    connection: options
  });
  const hook = require('knex-hooks');
  const helpers = require('knex-hooks').helpers;
  hook(knex);

  const databaseName = options.database;
  const dbColumns = await knex('information_schema.COLUMNS')
    .where({'TABLE_SCHEMA': databaseName})
    .select('table_name', 'column_name', 'data_type');
  const schema = {};
  for (const item of dbColumns) {
    if (!saas.isObject(schema[item['table_name']])) {
      schema[item['table_name']] = {};
    }
    schema[item['table_name']][item['column_name']] = item['data_type'];
  }
  saas.schema = schema;

  knex.addHook('before', ['insert', 'update'], '*', (when, method, table, params) => {
    let data;
    if (method === 'insert') {
      data = hook.helpers.getInsertData(params.query);
    } else if (method === 'update') {
      data = hook.helpers.getUpdateData(params.query);
    }
    saas.checkDbProp(table, data);
  })

  /**
   * thenUpdate
   * @param tableName
   * @param whereOptions
   * @param obj
   * @returns {Promise<*[]>}
   */
  knex.thenUpdate = async function (tableName, whereOptions, obj) {
    const queryData = await knex(tableName).where(whereOptions).first();
    if (!saas.isTrueEmpty(obj.id)) {
      delete obj.id;
    }
    if (saas.isEmpty(queryData)) {
      return await knex(tableName).insert(obj);
    } else {
      await knex(tableName).where(whereOptions).update(obj);
      if (!saas.isTrueEmpty(queryData.id)) {
        return [queryData.id];
      }
      return [0];
    }
  };

  helpers.extendBuilder(knex, function callback(builder, isRoot) {
    builder.page = function (page, pageSize) {
      return this.limit(pageSize).offset((page - 1) * pageSize);
    };

    builder.countSelect = async function (options) {
      const count = await this.count('*');
      const data = await this.clearSelect().select(options);
      return {count: count[0]['count(*)'], data: data};
    };
    
    builder.thenUpdate = async function(obj, where) {
      const queryData = await this.where(where).first();
      if (!saas.isTrueEmpty(obj.id)) {
        delete obj.id;
      }
      if (saas.isEmpty(queryData)) {
        return await this.insert(obj);
      } else {
        await this.where(where).update(obj);
        if (!saas.isTrueEmpty(queryData.id)) {
          return [queryData.id];
        }
        return [0];
      }
    };
  });

  fastify.decorate('mysql', knex);
}

module.exports = fp(mysqlKnex);
